/***************************************************************************/
/*                                                                         */
/*  pfrcmap.c                                                              */
/*                                                                         */
/*    FreeType PFR cmap handling (body).                                   */
/*                                                                         */
/*  Copyright 2002, 2007, 2009 by                                          */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


#include "pfrcmap.h"
#include "pfrobjs.h"

#include "pfrerror.h"


FT_CALLBACK_DEF(FT_Error)
pfr_cmap_init(PFR_CMap cmap)
{
    FT_Error error = PFR_Err_Ok;
    PFR_Face face = (PFR_Face)FT_CMAP_FACE(cmap);


    cmap->num_chars = face->phy_font.num_chars;
    cmap->chars = face->phy_font.chars;

    /* just for safety, check that the character entries are correctly */
    /* sorted in increasing character code order                       */
    {
        FT_UInt n;


        for (n = 1; n < cmap->num_chars; n++)
        {
            if (cmap->chars[n - 1].char_code >= cmap->chars[n].char_code)
            {
                error = PFR_Err_Invalid_Table;
                goto Exit;
            }
        }
    }

Exit:
    return error;
}


FT_CALLBACK_DEF(void)
pfr_cmap_done(PFR_CMap cmap)
{
    cmap->chars = NULL;
    cmap->num_chars = 0;
}


FT_CALLBACK_DEF(FT_UInt)
pfr_cmap_char_index(PFR_CMap cmap,
                    FT_UInt32 char_code)
{
    FT_UInt min = 0;
    FT_UInt max = cmap->num_chars;
    FT_UInt mid;
    PFR_Char gchar;


    while (min < max)
    {
        mid = min + (max - min) / 2;
        gchar = cmap->chars + mid;

        if (gchar->char_code == char_code)
            return mid + 1;

        if (gchar->char_code < char_code)
            min = mid + 1;
        else
            max = mid;
    }
    return 0;
}


FT_CALLBACK_DEF(FT_UInt32)
pfr_cmap_char_next(PFR_CMap cmap,
                   FT_UInt32 * pchar_code)
{
    FT_UInt result = 0;
    FT_UInt32 char_code = *pchar_code + 1;


Restart:
    {
        FT_UInt min = 0;
        FT_UInt max = cmap->num_chars;
        FT_UInt mid;
        PFR_Char gchar;


        while (min < max)
        {
            mid = min + ((max - min) >> 1);
            gchar = cmap->chars + mid;

            if (gchar->char_code == char_code)
            {
                result = mid;
                if (result != 0)
                {
                    result++;
                    goto Exit;
                }

                char_code++;
                goto Restart;
            }

            if (gchar->char_code < char_code)
                min = mid + 1;
            else
                max = mid;
        }

        /* we didn't find it, but we have a pair just above it */
        char_code = 0;

        if (min < cmap->num_chars)
        {
            gchar = cmap->chars + min;
            result = min;
            if (result != 0)
            {
                result++;
                char_code = gchar->char_code;
            }
        }
    }

Exit:
    *pchar_code = char_code;
    return result;
}


FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
pfr_cmap_class_rec =
{
    sizeof(PFR_CMapRec),

    (FT_CMap_InitFunc)pfr_cmap_init,
    (FT_CMap_DoneFunc)pfr_cmap_done,
    (FT_CMap_CharIndexFunc)pfr_cmap_char_index,
    (FT_CMap_CharNextFunc)pfr_cmap_char_next,

    NULL, NULL, NULL, NULL, NULL
};


/* END */